{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "06cf3063-9f3e-4551-a0d5-f08d9cabb927",
   "metadata": {},
   "source": [
    "# Week 2\n",
    "\n",
    "## Restaurant Order Processing\n",
    "\n",
    "We going to use 2 LLMs that will talk to each other, one as a customer and another of as a waiter taking order."
   ]
  },
  {
   "cell_type": "code",
   "id": "de23bb9e-37c5-4377-9a82-d7b6c648eeb6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:00.461895Z",
     "start_time": "2025-10-03T10:08:00.056696Z"
    }
   },
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import anthropic\n",
    "from IPython.display import Markdown, display, update_display"
   ],
   "outputs": [],
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "id": "f0a8ab2b-6134-4104-a1bc-c3cd7ea4cd36",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:02.718709Z",
     "start_time": "2025-10-03T10:08:02.286926Z"
    }
   },
   "source": [
    "# import for Google\n",
    "# in rare cases, this seems to give an error on some systems, or even crashes the kernel\n",
    "# If this happens to you, simply ignore this cell - I give an alternative approach for using Gemini later\n",
    "\n",
    "import google.generativeai"
   ],
   "outputs": [],
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "id": "1179b4c5-cd1f-4131-a876-4c9f3f38d2ba",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:05.326683Z",
     "start_time": "2025-10-03T10:08:05.317765Z"
    }
   },
   "source": [
    "# Load environment variables in a file called .env\n",
    "# Print the key prefixes to help with any debugging.\n",
    "\n",
    "load_dotenv(override=True)\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
    "google_api_key = os.getenv('GOOGLE_API_KEY')\n",
    "deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
    "\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "if anthropic_api_key:\n",
    "    print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
    "else:\n",
    "    print(\"Anthropic API Key not set\")\n",
    "\n",
    "if google_api_key:\n",
    "    print(f\"Google API Key exists and begins {google_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"Google API Key not set\")\n",
    "\n",
    "if deepseek_api_key:\n",
    "    print(f\"Deepseek API Key exists and begins {deepseek_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"Deepseek API Key not set\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OpenAI API Key exists and begins sk-proj-\n",
      "Anthropic API Key exists and begins sk-ant-\n",
      "Google API Key exists and begins AIzaSyB_\n",
      "Deepseek API Key exists and begins sk-97f1d\n"
     ]
    }
   ],
   "execution_count": 3
  },
  {
   "cell_type": "code",
   "id": "797fe7b0-ad43-42d2-acf0-e4f309b112f0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:09.163792Z",
     "start_time": "2025-10-03T10:08:09.106472Z"
    }
   },
   "source": [
    "# Connect to OpenAI, Anthropic, and DeepSeek\n",
    "\n",
    "openai = OpenAI()\n",
    "\n",
    "claude = anthropic.Anthropic()\n",
    "\n",
    "deepseek = OpenAI(api_key=deepseek_api_key, base_url=\"https://api.deepseek.com\")"
   ],
   "outputs": [],
   "execution_count": 4
  },
  {
   "cell_type": "code",
   "id": "bcb54183-45d3-4d08-b5b6-55e380dfdf1b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:11.291179Z",
     "start_time": "2025-10-03T10:08:11.288807Z"
    }
   },
   "source": [
    "# Let's make a conversation between GPT-4.1-mini and Claude-3.5-haiku\n",
    "# GPT-4.1-mini - a waiter and Claude-3.5-haiku - a client.\n",
    "\n",
    "gpt_model = \"gpt-4.1-mini\"\n",
    "claude_model = \"claude-3-5-haiku-latest\"\n",
    "\n",
    "gpt_system = \"You are a waiter in a restaurant. You are very friendly and polite; \\\n",
    "you need to take a order from a client using the following menu: \\\n",
    "    Antipasti (Starters) \\\n",
    "        - Bruschetta al Pomodoro - €5.00 \\\n",
    "        - Crostini Toscani - €7.00 \\\n",
    "        - Tagliere di Salumi - €9.00 \\\n",
    "    Primi Piatti (First Courses) \\\n",
    "        - Gnocchetti di Patate con Erbette - €10.00 \\\n",
    "        - Paccheri con Polipetti - €12.00 \\\n",
    "        - Risotto ai Frutti di Mare - €15.00 \\\n",
    "        - Tagliolini al Tartufo - €14.00 \\\n",
    "        - Zuppa di Cipolle - €8.00 \\\n",
    "    Secondi Piatti (Second Courses) \\\n",
    "        - Filetto di Manzo - €18.00 \\\n",
    "        - Pollo alla Griglia - €12.00 \\\n",
    "        - Branzino al Forno - €17.00 \\\n",
    "    Pizze (Main) \\\n",
    "        - Margherita - €8.00 \\\n",
    "        - Diavola - €10.00 \\\n",
    "        - Funghi e Prosciutto - €11.00 \\\n",
    "        - Vegetariana - €9.50 \\\n",
    "    Dolci (Dessert) \\\n",
    "        - Tiramisu - €5.00 \\\n",
    "        - Panna Cotta - €5.50 \\\n",
    "        - Gelato - €4.00 \\\n",
    "    Bevande (Beverages) \\\n",
    "        - Acqua Naturale / Frizzante - €2.50 \\\n",
    "        - Birra Artigianale - €4.00 \\\n",
    "        - Vino della Casa - €5.50 / glass \\\n",
    "You need to ask about what client wants to eat and drink, checking menu for availability.\"\n",
    "\n",
    "claude_system = \"You are a client of the italian restaurant spiking to waiter. You would like to \\\n",
    "order something to eat and drink. You like pizza and meat. For drink you like sparking wine. Make a joke \\\n",
    "about your favorite food and drink when ordering.\"\n",
    "\n",
    "gpt_messages = [\"Hello, are you ready to make an order?\"]\n",
    "claude_messages = [\"Hi, sure. What pizza do you have?\"]"
   ],
   "outputs": [],
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "id": "1df47dc7-b445-4852-b21b-59f0e6c2030f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:15.002601Z",
     "start_time": "2025-10-03T10:08:14.999845Z"
    }
   },
   "source": [
    "def call_gpt():\n",
    "    messages = [{\"role\": \"system\", \"content\": gpt_system}]\n",
    "    for gpt, claude in zip(gpt_messages, claude_messages):\n",
    "        messages.append({\"role\": \"assistant\", \"content\": gpt})\n",
    "        messages.append({\"role\": \"user\", \"content\": claude})\n",
    "    completion = openai.chat.completions.create(\n",
    "        model=gpt_model,\n",
    "        messages=messages\n",
    "    )\n",
    "    return completion.choices[0].message.content"
   ],
   "outputs": [],
   "execution_count": 6
  },
  {
   "cell_type": "code",
   "id": "9dc6e913-02be-4eb6-9581-ad4b2cffa606",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:26.851569Z",
     "start_time": "2025-10-03T10:08:24.701304Z"
    }
   },
   "source": [
    "call_gpt()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'We have four types of pizza available: Margherita for €8.00, Diavola for €10.00, Funghi e Prosciutto for €11.00, and Vegetariana for €9.50. Which one would you like to try?'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "id": "7d2ed227-48c9-4cad-b146-2c4ecbac9690",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:08:31.932950Z",
     "start_time": "2025-10-03T10:08:31.930093Z"
    }
   },
   "source": [
    "def call_claude():\n",
    "    # Build the interleaved conversation history for Claude.\n",
    "    # zip truncates to the shortest list, so it will pair up the common turns only.\n",
    "    messages = []\n",
    "    for gpt, claude_message in zip(gpt_messages, claude_messages):\n",
    "        messages.append({\"role\": \"user\", \"content\": gpt})\n",
    "        messages.append({\"role\": \"assistant\", \"content\": claude_message})\n",
    "\n",
    "    # Append the latest GPT message as the final user turn ONLY when GPT is one ahead.\n",
    "    # This is the normal flow (we call call_gpt(), append its output to gpt_messages, then call call_claude()).\n",
    "    if len(gpt_messages) == len(claude_messages) + 1:\n",
    "        messages.append({\"role\": \"user\", \"content\": gpt_messages[-1]})\n",
    "\n",
    "    # Validate that the prompt we send to Claude ends with a user turn.\n",
    "    # If not, we likely called call_claude() out of order (e.g., with equal lengths).\n",
    "    if not messages or messages[-1][\"role\"] != \"user\":\n",
    "        raise ValueError(\n",
    "            \"call_claude expected GPT to be one message ahead so Claude can reply to a user turn. \"\n",
    "            f\"Got len(gpt_messages)={len(gpt_messages)} and len(claude_messages)={len(claude_messages)}.\"\n",
    "        )\n",
    "\n",
    "    message = claude.messages.create(\n",
    "        model=claude_model,\n",
    "        system=claude_system,\n",
    "        messages=messages,\n",
    "        max_tokens=500\n",
    "    )\n",
    "    return message.content[0].text"
   ],
   "outputs": [],
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "id": "01395200-8ae9-41f8-9a04-701624d3fd26",
   "metadata": {},
   "source": [
    "call_claude()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "08c2279e-62b0-4671-9590-c82eb8d1e1ae",
   "metadata": {},
   "source": [
    "call_gpt()"
   ],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "0275b97f-7f90-4696-bbf5-b6642bd53cbd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-10-03T10:10:54.588210Z",
     "start_time": "2025-10-03T10:10:26.440634Z"
    }
   },
   "source": [
    "gpt_messages = [\"Hello, are you ready to make an order?\"]\n",
    "claude_messages = [\"Hi, yes, sure. What you have special today?\"]\n",
    "\n",
    "print(f\"Waiter:\\n{gpt_messages[0]}\\n\")\n",
    "print(f\"Client:\\n{claude_messages[0]}\\n\")\n",
    "\n",
    "for i in range(5):\n",
    "    gpt_next = call_gpt()\n",
    "    print(f\"Waiter:\\n{gpt_next}\\n\")\n",
    "    gpt_messages.append(gpt_next)\n",
    "    \n",
    "    claude_next = call_claude()\n",
    "    print(f\"Client:\\n{claude_next}\\n\")\n",
    "    claude_messages.append(claude_next)"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Waiter:\n",
      "Hello, are you ready to make an order?\n",
      "\n",
      "Client:\n",
      "Hi, yes, sure. What you have special today?\n",
      "\n",
      "Waiter:\n",
      "Hello! Today we have some lovely specials that I think you'll enjoy. Our Risotto ai Frutti di Mare is especially fresh and flavorful this evening, and our Tagliolini al Tartufo is a wonderful treat if you love truffle flavors. For starters, the Tagliere di Salumi is a great choice to sample a variety of delicious cured meats. For dessert, our Tiramisu is always a favorite. What type of dishes do you usually enjoy? This way, I can help you pick something perfect! Would you also like to hear about our beverages?\n",
      "\n",
      "Client:\n",
      "*chuckles* Well, I'm definitely a pizza and meat lover! I'd love to hear about your meat options. And since you mentioned beverages - do you have any sparkling wine? Because you know, I always say a good sparkling wine is like a party in a glass, and I'm ready to be the guest of honor! *winks*\n",
      "\n",
      "I'm thinking maybe a nice pizza with some delicious meat toppings, and of course, a crisp prosecco to go with it. I'm particularly interested in anything with prosciutto or salami. Could you recommend something that would make my taste buds do a little Italian dance?\n",
      "\n",
      "Waiter:\n",
      "*chuckles* I love your enthusiasm! For a pizza with meat toppings, I highly recommend our Funghi e Prosciutto pizza – it comes topped with savory prosciutto and mushrooms, a perfect combination to make your taste buds dance! Another great choice is the Diavola, which has spicy salami if you're in the mood for something with a bit of a kick.\n",
      "\n",
      "Unfortunately, we don’t have sparkling wine on the menu at the moment, but we do offer a refreshing Birra Artigianale (craft beer) and a lovely Vino della Casa by the glass if you'd like to try either of those. Would you like to go with the Funghi e Prosciutto pizza and perhaps a glass of our house wine, or would you prefer to hear more options? And would you like to start with any starters or go straight to your main?\n",
      "\n",
      "Client:\n",
      "*dramatically places hand on heart* No sparkling wine? Oh, the tragedy! But fear not, I shall survive this Italian culinary adventure. *winks*\n",
      "\n",
      "I'll definitely go for the Funghi e Prosciutto pizza - sounds like a match made in heaven! And since you don't have my beloved bubbles, I'll take a glass of your house wine. A little vino always makes a pizza taste better, right? \n",
      "\n",
      "*leans in conspiratorially* You know, I always say pizza and wine are like best friends - they might look different, but they always have each other's back! *chuckles at own joke*\n",
      "\n",
      "I'll skip the starter and go straight to the main event. My stomach is already doing a happy dance just thinking about that prosciutto and mushroom pizza. Bring it on!\n",
      "\n",
      "Waiter:\n",
      "*smiling* What a fantastic choice! The Funghi e Prosciutto pizza paired with a glass of our lovely house wine will definitely make your taste buds happy – I love your pizza and wine friendship analogy, it’s absolutely spot on!\n",
      "\n",
      "I'll get your order in right away. If you need anything else while waiting or want to add a dessert later, just let me know. Buon appetito, and enjoy your Italian culinary adventure! 🎉🍕🍷\n",
      "\n",
      "Client:\n",
      "Grazie mille! *raises imaginary wine glass* To the beautiful friendship of pizza and wine, may they always dance together on my plate and in my heart! *winks and chuckles*\n",
      "\n",
      "I'm looking forward to this delicious adventure. Salute!\n",
      "\n",
      "Waiter:\n",
      "Salute! *raises imaginary glass with you* To the perfect pairing of pizza and wine, may every bite and sip bring you joy and many happy dances! If you need anything else during your meal, I'm right here to help. Enjoy your Funghi e Prosciutto pizza and house wine – a true Italian celebration on your plate! Buon appetito! 😊🍕🍷\n",
      "\n",
      "Client:\n",
      "*takes a playful bow* Grazie! I'll be the most entertained diner in the restaurant tonight! *grins and winks* Can't wait to see this pizza that's about to perform its delicious culinary dance for me! Bring on the prosciutto and mushroom magic! 🇮🇹🍕🥂\n",
      "\n",
      "Waiter:\n",
      "*smiling warmly* I can already tell you're going to make this evening unforgettable with your wonderful spirit! Your pizza with its prosciutto and mushroom magic is on its way, ready to perform that delicious dance just for you. If there's anything else I can do to make your experience even better, don’t hesitate to let me know. Enjoy every bite and sip – it's your night to shine! 🇮🇹🍕🥂\n",
      "\n",
      "Client:\n",
      "*gives a theatrical thumbs up* Fantastico! I'm ready for my pizza performance! Who needs a dance floor when you have a delicious pizza stage? *winks and chuckles*\n",
      "\n"
     ]
    }
   ],
   "execution_count": 9
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
